# -*- coding: utf-8 -*-
# @Time    : 2024/10/29 14:57
# @Author  : CHNJX
# @File    : __init__.py.py
# @Desc    : 应用工厂


# app/__init__.py
import logging
import os
import gc
import atexit
from logging.handlers import RotatingFileHandler

from flask import Flask, g
from flask_cors import CORS

from .core.scheduler import SchedulerService
from .api.routes import bp
from .utils.database import db, migrate
from .config import config

# 使用全局变量但确保仅初始化一次
scheduler_service = None
_is_initialized = False


def create_app(config_name=None):
    global scheduler_service, _is_initialized

    app = Flask(__name__)

    # 使用默认配置如果没有指定配置名
    if config_name is None:
        config_name = 'default'

    app.config.from_object(config[config_name])

    # 配置日志系统
    configure_logging(app)

    # 在这里配置 CORS，而不是在运行文件中
    CORS(app, resources={
        r"/*": {
            "origins": "*",  # 允许所有来源
            "supports_credentials": True,
            "allow_headers": ["Content-Type", "Authorization", "X-Requested-With"],
            "expose_headers": ["Content-Range", "X-Content-Range"],
            "methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
            "max_age": 600
        }
    })

    # 如果存在 .env 文件，加载环境变量配置
    app.config.from_prefixed_env()

    # 初始化数据库
    db.init_app(app)
    migrate.init_app(app, db)

    # 确保关键配置项存在
    assert 'JENKINS_JOB_NAME' in app.config, "JENKINS_JOB_NAME must be set"
    assert 'JENKINS_URL' in app.config, "JENKINS_URL must be set"
    assert 'JENKINS_USER' in app.config, "JENKINS_USER must be set"
    assert 'JENKINS_PASSWORD' in app.config, "JENKINS_PASSWORD must be set"

    # 初始化 scheduler_service (只初始化一次)
    if scheduler_service is None:
        scheduler_service = SchedulerService(app)

    # 注册蓝图
    app.register_blueprint(bp, url_prefix='/api')
    
    # 注册功能测试管理API蓝图
    try:
        from .api.routes.test_management import test_management_bp
        
        # 注册测试管理蓝图
        app.register_blueprint(test_management_bp, url_prefix='/api/test-management')
        app.logger.info("功能测试管理API路由已注册")
        
    except ImportError as e:
        app.logger.warning(f"功能测试管理模块未找到: {str(e)}")
    except Exception as e:
        app.logger.error(f"注册功能测试管理API时出错: {str(e)}")
    
    # 注册应用关闭时的资源清理函数
    register_cleanup_handlers(app)
    
    # 定期触发垃圾回收以防止内存泄漏
    @app.before_request
    def before_request():
        # 每100次请求触发一次垃圾回收
        if not hasattr(g, 'request_counter'):
            g.request_counter = 0
        g.request_counter += 1
        
        if g.request_counter % 100 == 0:
            app.logger.debug(f"执行定期垃圾回收 (请求计数: {g.request_counter})")
            gc.collect()

    # 标记全局初始化完成
    _is_initialized = True
    
    return app


def configure_logging(app):
    """配置应用的日志系统"""
    # 确保日志目录存在
    if not os.path.exists('logs'):
        os.mkdir('logs')

    # 设置日志格式
    formatter = logging.Formatter(
        '%(asctime)s %(levelname)s: %(message)s '
        '[in %(pathname)s:%(lineno)d]'
    )

    # 配置文件处理器
    file_handler = RotatingFileHandler(
        'logs/auto_test.log',
        maxBytes=10240000,
        backupCount=10
    )
    file_handler.setFormatter(formatter)
    file_handler.setLevel(logging.INFO)

    # 配置控制台处理器
    console_handler = logging.StreamHandler()
    console_handler.setFormatter(formatter)
    console_handler.setLevel(logging.DEBUG)  # 控制台显示更详细的日志级别

    # 清除现有的处理器（避免重复）
    app.logger.handlers.clear()

    # 添加处理器到应用日志记录器
    app.logger.addHandler(file_handler)
    app.logger.addHandler(console_handler)

    # 设置日志级别为 DEBUG（这样可以看到所有级别的日志）
    app.logger.setLevel(logging.DEBUG)

    # 设置 Werkzeug 日志记录器的级别为 DEBUG
    logging.getLogger('werkzeug').setLevel(logging.DEBUG)

    # 添加一些测试日志，确认日志系统正常工作
    app.logger.debug('Debug message - 这是一条调试日志')
    app.logger.info('Info message - Auto Test Platform startup')
    app.logger.warning('Warning message - 这是一条警告日志')


def register_cleanup_handlers(app):
    """注册资源清理处理程序"""
    # 应用上下文结束时清理资源
    @app.teardown_appcontext
    def cleanup_resources(exception=None):
        """在应用上下文结束时清理资源"""
        # 释放数据库会话
        if db.session is not None:
            try:
                db.session.remove()
                app.logger.debug("数据库会话已清理")
            except Exception as e:
                app.logger.error(f"清理数据库会话时出错: {str(e)}")
                
        # 触发垃圾回收
        gc.collect()
    
    # Python解释器退出时的清理
    def cleanup_on_exit():
        # 确保调度器服务被正确停止
        global scheduler_service
        if scheduler_service is not None:
            try:
                scheduler_service.cleanup()
                logging.info("调度器服务已在退出时清理")
            except Exception as e:
                logging.error(f"退出时清理调度器服务出错: {str(e)}")
                
        # 最终垃圾回收
        gc.collect()
        logging.info("应用退出时资源清理完成")
    
    # 注册退出处理程序
    atexit.register(cleanup_on_exit)